package com.xing.async;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;

/**
 * 异步操作管理器
 * 主线程处理非耗时操作，耗时操作交由子线程负责处理
 * 
 */
public class AsyncManagerImpl extends AbstractManager implements IAsyncManager {

    private static final Logger logger = LoggerFactory.getLogger("async");

    /** 位于主线程的消息处理器,用于当异步操作完成后,在主线程中执行收尾操作 */
    private final IMessageProcessor messageProcessor;
    /** 与玩家角色绑定的线程池,即根据玩家角色的id号{@linkPlayerCharacter#getId()},固定的操作总在同一个线程池中运行 */
    private final ExecutorService[] charBindExecutors;
    /** 不与玩家角色绑定的线程池 */
    private final ExecutorService charUnBindExecutor;

    public AsyncManagerImpl(final int charBindExecutorSize, final int charUnBindExecutorSize,
            IMessageProcessor messageProcessor) {
        charBindExecutors = new ExecutorService[charBindExecutorSize];
        for (int i = 0; i < charBindExecutorSize; i++) {
            charBindExecutors[i] = Executors.newSingleThreadExecutor();
        }

        this.messageProcessor = messageProcessor;
        this.charUnBindExecutor =
                new ThreadPoolExecutor(
                        charUnBindExecutorSize,
                        charUnBindExecutorSize * 20,
                        120L,
                        TimeUnit.SECONDS,
                        new ArrayBlockingQueue<>(10000)
                );
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.mop..gameserver.async.IAsyncManager#createOperation(com.mop.
     * .gameserver.async.IIoOperation)
     */
    public AsyncOperation createOperation(IIoOperation operation) {
        if (operation instanceof ICharOperation) {
            int _charId = ((ICharOperation) operation).getCharId();
            int _executorIndex = _charId % this.charBindExecutors.length;
            ExecutorService _asyncExecutor = this.charBindExecutors[_executorIndex];
            if (logger.isDebugEnabled()) {
                logger.debug("[#GS.AsyncManagerImpl.createOperation] [char:" + _charId + " bind to executor :"
                        + _executorIndex + "]");
            }
            return new AsyncOperation(operation, _asyncExecutor, messageProcessor);
        } else {
            return new AsyncOperation(operation, charUnBindExecutor, messageProcessor);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.mop..gameserver.async.IAsyncManager#createOperationAndExecuteAtOnce
     * (com.mop..gameserver.async.IIoOperation)
     */
    public AsyncOperation createOperationAndExecuteAtOnce(IIoOperation operation) {
        AsyncOperation _operation = this.createOperation(operation);
        _operation.execute();
        return _operation;
    }

    @Override
    public SyncOperation createSyncOperationAndExecuteAtOnce(IIoOperation operation) {
        SyncOperation _operation = new SyncOperation(operation);
        _operation.execute();
        return _operation;
    }

    @Override
    public void check() {}

    @Override
    public void init() {}

    @Override
    public void stop() {
        try {
            for (ExecutorService _executor : this.charBindExecutors) {
                _executor.shutdown();
            }
            this.charUnBindExecutor.shutdown();
        } catch (Exception e) {
            if (logger.isErrorEnabled()) {
            }
        }
    }
}
